/*
 * Copyright 2020 zytech
 * All rights reserved.
 *
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include "erpc_manually_constructed.h"
#include "erpc_dual_serial_transport.h"
#include "erpc_setup_dual_serial.h"
#include "erpc_threading.h"

using namespace erpc;

////////////////////////////////////////////////////////////////////////////////
// Variables
////////////////////////////////////////////////////////////////////////////////

Semaphore server_semaphore(0);  /*!< server receive semaphore. */
Semaphore client_semaphore(0);  /*!< client receive semaphore. */
Semaphore switch_semaphore(1);  /*!< semaphore for switch thread. */
Mutex send_lock;                /*!< send lock shared by client and server. */
static ManuallyConstructed<DualSerialTransport> s_transport; /*!< transport for server side. */
static ManuallyConstructed<DualSerialTransport> c_transport; /*!< transport for client side. */
////////////////////////////////////////////////////////////////////////////////
// Code
////////////////////////////////////////////////////////////////////////////////

erpc_status_t erpc_transport_dual_serial_init(const char *portName, long baudRate)
{
    const uint8_t vtime = 0;
    const uint8_t vmin = 1;
	int serialHandle = -1;
    // construct transport for server side
    s_transport.construct(portName, baudRate, true);
    erpc_status_t status = s_transport->init(vtime, vmin, &serialHandle);
    if (status != kErpcStatus_Success)
    {
        return status;
    }
	status = s_transport->configure(&server_semaphore, &switch_semaphore, &send_lock,&client_semaphore);
    if (status != kErpcStatus_Success)
    {
        return status;
    }
	s_transport->open();
    // construct transport for client side
    c_transport.construct(portName, baudRate, false);
    // initialize client transport with serialHandle that be initialized by server transport
	status = c_transport->init(vtime, vmin,&serialHandle);
	if (status != kErpcStatus_Success)
	{
		return status;
	}
	status = c_transport->configure(&client_semaphore, &switch_semaphore,&send_lock, NULL);
    return status;
}

erpc_status_t erpc_transport_dual_serial_deinit(void)
{
	s_transport->close();
	c_transport->close();
	return kErpcStatus_Success;
}
erpc_transport_t erpc_transport_dual_serial_get(bool isServer)
{
	if(isServer)
	{
		return reinterpret_cast<erpc_transport_t>(s_transport.get());
	}else{
		return reinterpret_cast<erpc_transport_t>(c_transport.get());
	}
}
